/**
 * Entity类，用于管理组件状态和触发渲染
 * 类似于Zed GPUI中的Entity<T>，是实现cx.notify的核心
 */
import { Context, AppContext } from './context';
import { Scene } from './scene';

/**
 * 实体类，封装组件状态和Context
 */
export class Entity<T> {
  private id: string;
  private appContext: AppContext;
  private value: T;
  private scene?: Scene;

  constructor(id: string, appContext: AppContext, value: T) {
    this.id = id;
    this.appContext = appContext;
    this.value = value;
  }

  /**
   * 获取实体ID
   */
  getId(): string {
    return this.id;
  }

  /**
   * 设置场景关联
   */
  setScene(scene: Scene): void {
    this.scene = scene;
  }

  /**
   * 获取实体值（只读访问）
   * 类似于Zed GPUI中的read方法
   */
  read<R>(callback: (value: T) => R): R {
    return callback(this.value);
  }

  /**
   * 更新实体值并触发通知
   * 类似于Zed GPUI中的update方法
   */
  update<R>(callback: (value: T, cx: Context<T>) => R): R {
    const context = new Context<T>(this.id, this.appContext, this.value);
    const result = callback(this.value, context);
    
    // 通知系统实体已更新
    context.notify();
    
    // 如果有关联的场景，通知场景更新
    if (this.scene) {
      this.scene.notifyUpdate();
    }
    
    return result;
  }

  /**
   * 获取当前实体值的引用
   * 注意：直接修改返回值不会触发通知，应使用update方法
   */
  getValue(): T {
    return this.value;
  }

  /**
   * 设置实体值
   * 注意：此方法不会触发通知，应使用update方法
   */
  setValue(value: T): void {
    this.value = value;
  }
}

/**
 * Render trait接口，类似于Zed GPUI中的Render trait
 * 实现此接口的组件可以定义自己的渲染逻辑
 */
export interface Renderable {
  render(): Scene;
}

/**
 * 创建新实体的工厂函数
 * 类似于Zed GPUI中的cx.new方法
 */
export function createEntity<T>(
  appContext: AppContext,
  initialValue: T,
  scene?: Scene
): Entity<T> {
  const id = `entity_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  const entity = new Entity<T>(id, appContext, initialValue);
  
  if (scene) {
    entity.setScene(scene);
    scene.setContext(new Context<T>(id, appContext, initialValue));
  }
  
  return entity;
}